package com.googlecode.hypersphere.ws2ejb3.xml;

import java.io.File;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;

public class MapxmiParser {

	private final Document doc;
	private final File dir;
	private Query query;

	/**
	 * @param dir
	 *            the parent directory of 'META-INF'
	 * @param path
	 *            the path to the file to parse
	 */
	public MapxmiParser(File dir, String path, Query query) {
		this.query = query;
		this.dir = dir;
		File file = new File(dir.getAbsolutePath() + "/" + path);
		SAXReader xmlReader = new SAXReader();
		try {
			doc = xmlReader.read(file);
		} catch (DocumentException e) {
			throw new IllegalArgumentException(e);
		}
	}

	public Link getEntityLink(String id) {
		query.setQuery("/*/nested[@xmi:id='" + id + "']/outputs/@href");
		String string = query.valueOf(doc);
		return Link.createLink(string);
	}

	/**
	 * @param id
	 *            an id e.g. 'CMPAttribute_1195637375126'
	 * @param name
	 *            the name of the member variable e.g. 'title'
	 * @return a new field object
	 */
	public Field getField(String id, String name) {
		query.setQuery("/*/nested/nested/inputs[@href='META-INF/ejb-jar.xml#"
				+ id + "']/parent::*/typeMapping/@href");
		String typeString = query.valueOf(doc);
		query.setQuery("/*/nested/nested/inputs[@href='META-INF/ejb-jar.xml#"
				+ id + "']/parent::*/outputs/@href");
		String linkString = query.valueOf(doc);
		Link link = Link.createLink(linkString);
		MapxmiParser tableParser = new MapxmiParser(dir, link.getPath(), query);
		boolean isPrimaryKey = tableParser.isPrimaryKey(link.getId());
		return Field.createField(typeString, name, link, isPrimaryKey);
	}

	private boolean isPrimaryKey(String id) {
		query.setQuery("/*/constraints[@type='PRIMARYKEY']/@xmi:id");
		String primaryKeyId = query.valueOf(doc);
		query.setQuery("/*/namedGroup[@constraint='" + primaryKeyId
				+ "']/@members");
		String members = query.valueOf(doc);
		// combined primary keys are separated by the space-character
		String[] primaryKeys = members.split(" ");
		for (int i = 0; i < primaryKeys.length; i++) {
			if (primaryKeys[i].equals(id))
				return true;
		}
		return false;
	}

	public void setQuery(Query query) {
		this.query = query;
	}

	/**
	 * @param id the id of the relationship e.g. 'EJBRelation_1195637517251'
	 * @return a new relationship object
	 */
	public Relationship getRelationship(String id) {
		Relationship relationship = new Relationship();
		query.setQuery("/*/nested/nested/inputs[@href='META-INF/ejb-jar.xml#"
				+ id + "']/parent::*/outputs/@href");
		String linkString = query.valueOf(doc);
		Link link = Link.createLink(linkString);
		// this parser works on the table-mapping file
		MapxmiParser parser = new MapxmiParser(dir, link.getPath(), query);
		relationship.setTableName(parser.getTableName());
		relationship.setJoinColumn(parser.getJoinColumn(link.getId()));
		return relationship;
	}

	private String getJoinColumn(String id) {
		query.setQuery("/*/namedGroup[@xmi:id='" + id + "']/@members");
		String member = query.valueOf(doc);
		query.setQuery("/*/columns[@xmi:id='" + member + "']/@name");
		return query.valueOf(doc);
	}

	private String getTableName() {
		query.setQuery("/*/@name");
		return query.valueOf(doc);
	}

	/**
	 * @param entityName
	 * @return the name of database table
	 */
	public String getEntityTableName(String entityName) {
		query.setQuery("/*/nested/inputs[@href='META-INF/ejb-jar.xml#"
				+ entityName + "']/parent::*/outputs/@href");
		String linkString = query.valueOf(doc);
		Link link = Link.createLink(linkString);
		MapxmiParser parser = new MapxmiParser(dir, link.getPath(), query);
		return parser.getTableName();
	}

}
